﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Collections.ObjectModel;
using System.Reflection;

namespace Fonlow.CommandLineGui
{

    /// <summary>
    /// Load assemblies with implementations of CommandBase and Options, and create instances of CommandBase
    /// </summary>
    public sealed class TypeLoader
    {
        private TypeLoader()
        {
        }

        /// <summary>
        /// Load assemblies with implementations of IConfigurationRoot, and create instances of IConfigurationRoot
        /// </summary>
        public static CommandBase LoadAssemblyWithCommand(string assemblyName)
        {

            string typeName = typeof(CommandBase).FullName;

            Assembly assembly = null;
            try
            {
                assembly = Assembly.Load(assemblyName);
                System.Diagnostics.Trace.WriteLine(String.Format("Assembly {0} is loaded for type {1}.", assemblyName, typeName));
            }
            catch (System.IO.FileLoadException e)
            {
                System.Diagnostics.Trace.TraceWarning(String.Format("When loading {0}, errors occur: {1}", assemblyName, e.Message));
                return null;
            }
            catch (BadImageFormatException e)
            {
                System.Diagnostics.Trace.TraceWarning(String.Format("When loading {0}, errors occur: {1}", assemblyName, e.Message));
                //when file is a win32 dll.
                return null;
            }
            catch (System.IO.FileNotFoundException e)
            {
                System.Diagnostics.Trace.TraceWarning(String.Format("When loading {0}, errors occur: {1}", assemblyName, e.Message));
                return null;
            }


            try
            {
                foreach (Type type in assembly.GetTypes())
                {
                    if ((type.IsClass) && (typeof(CommandBase).IsAssignableFrom(type)))
                    {
                        CommandBase command = (CommandBase)assembly.CreateInstance(type.FullName);
                        if (command != null)
                        {
                            return command;
                        }
                    }
                }
            }
            catch (ReflectionTypeLoadException e)
            {
                foreach (Exception ex in e.LoaderExceptions)
                {
                    System.Diagnostics.Trace.TraceWarning(String.Format("When loading {0}, GetTypes errors occur: {1}", assemblyName, ex.Message));
                }
            }
            catch (TargetInvocationException e)
            {
                System.Diagnostics.Trace.TraceWarning(String.Format("When loading {0}, GetTypes errors occur: {1}", assemblyName, e.Message + "~~" + e.InnerException.Message));
            }

            return null;
        }


    }


}
